package simpledb.parse;

import simpledb.planner.Planner;
import simpledb.query.Plan;
import simpledb.tx.Transaction;

/**
 * The SimpleDB parser.
 * @author Kenneth J. Loomis
 * @version 12/9/2011
 */
public class PreParser {
   private String qry;
   private Boolean optimized;
   
   private Boolean preceding ( int start )
   {
	   Boolean rtn = false;
	   Boolean badChar = false;
	   
	   for ( int i = start; i > 0 && !rtn & !badChar; i--)
	   {
		   switch ( qry.charAt(i) )
		   {
		   		case ' ':
		   		case '\t':
		   		case '\n': break;
		   		case '=':
		   		case '<':
		   		case '>': rtn = true; break;
		   		default: badChar = true;
		   }
	   }
	   return rtn;
   }
   
   public PreParser( String s ) {
      this.qry = s;
      this.optimized = false;
   }
   
   public Boolean isOptimized ()
   {
	   return optimized;
   }
   
   public String optimized ( )
   {
       int findPara1, findPar2;
       findPara1 = findPar2 = -1;
	   if ( qry.toLowerCase().startsWith( "opt" ) )
 	   {
		      for(int i = 0; i < qry.length(); i++)
		      {
		    	  if( findPara1 < 0 && qry.charAt(i) == '(' )
		    	  {
		    		  findPara1 = i;
		    	  }
		    	  else if ( qry.charAt(i) == ')' )
				  {
					  findPar2 = i;
				  }
		      }
		      // Clean up the parentheses 
		      if ( findPara1 < findPar2)
		      {
				  qry = qry.substring(findPara1+1, findPar2);
				  optimized = true;
		      }
 	   }
	   return qry;
   }
   
   public String parse ( Planner planner, Transaction tx )
   {
       String tmp = "";
	   Boolean done = false;
	   
	   while (!done)
	   {
		   ParenPairs pp[] = new ParenPairs[100];
		   int paraCnt = 0;
		   for(int i = 0; i < qry.length(); i++)
		   {
			   if ( qry.charAt(i) == '(' )
			   {
				   pp[ paraCnt ] = new ParenPairs();
				   pp[ paraCnt ].SetLeft( i );
				   paraCnt++;
			   }
			   else if ( qry.charAt(i) == ')' )
			   {
				   for (int ii = paraCnt-1; ii >= 0; ii-- )
				   {
					   if ( pp[ii].GetRight( ) == -1)
					   {
						   pp[ ii ].SetRight( i );
					   }
				   }
				   
			   }
		   }
		   
		   if ( paraCnt > 0 )
		   {
			   int leftP, rightP;
			   leftP = pp[paraCnt-1].GetLeft(); 
			   rightP = pp[paraCnt-1].GetRight();
			   // Check for preceding operator to see if its a
			   //	right-hand side of an operation.
			   if ( !preceding( leftP-1 ) )
			   {
				   Plan p;
				   String tableName;

				   // That means it must be a temp table sub-query
				   String cmd = qry.substring( leftP+1, rightP-1 );
				   p = planner.createQueryPlan( cmd, tx);
				   tableName = planner.addTempTable(p);
				   if ( leftP-1 > 0 )
					   tmp = qry.substring(0, leftP-1 );
				   tmp += " " + tableName + " ";
				   
				   if ( rightP+1 < qry.length() )
					   tmp += qry.substring( rightP+1, qry.length() );
				   qry = tmp;
			   }
			   else
			   {
				   // Simply remove unneeded parentheses
				   if ( leftP-1 > 0 )
					   tmp = qry.substring(0, leftP );
				   tmp += qry.substring( leftP+1, rightP-1 );
				   if ( rightP+1 < qry.length() )
					   tmp += qry.substring( rightP+1, qry.length() );
				   qry = tmp; 
			   }
			   
		   }
		   else done = true;
	   }

	   return qry;
   }
   	
}
   


